﻿/*
 * 参考: https://www.grpc.io/docs/
 */

#include <iostream>
#include <memory>
#include <string>

#include <grpcpp/grpcpp.h>

// xxx.grpc.pb.h文件通过protoc.exe和grpc_cpp_plugin.exe编译得到
// 然后手动复制到项目文件夹下,并手动添加到解决方案!
#include "hello.grpc.pb.h"
#include "vno.grpc.pb.h"

// grpc提供的类型(供服务端使用)
using grpc::Server;
using grpc::ServerBuilder;
using grpc::ServerContext;
using grpc::Status;

// 在hello.grppc.pb.h中定义(与hello.proto定义一致)
using hello::HelloRequest;
using hello::HelloReply;
using hello::GreetService;

// 在vno.grppc.pb.h中定义(与vno.proto定义一致)
using vno::VnoRequest;
using vno::VnoReply;
using vno::VnoService;

/*
// hello.proto
// GreetService服务定义
service GreetService {
	// 简单问候
	rpc SayHello (HelloRequest) returns (HelloReply) {
	}
	// 增加更多的rpc定义
	// ...
}

// 用户请求(输入)
message HelloRequest {
	// 姓名
	string name = 1;
	// 增加更多的字段
	// ...
}

// 响应结果(输出)
message HelloReply {
	// 消息
	string message = 1;
	// 增加更多的字段
	// ...
}
*/

// 实现hello.proto/GreetService服务
class GreeterServiceImpl final : public GreetService::Service {
	// 实现SayHello调用
	// 参数:
	//	context -- 服务器调用上下文
	//	request -- 用户请求(输入)(参见hello.proto/HelloRequest定义)
	//	reply   -- 响应结果(输出)(参见hello.proto/HelloReply定义)
	Status SayHello(ServerContext* context, const HelloRequest* request, HelloReply* reply) override {
		// 1) 从request中提取数据,进行相关计算
		//    参考1: 区分 Protobuf 中缺失值和默认值(https://zhuanlan.zhihu.com/p/46603988)
		//    参考2: proto3默认值与可选项(https://www.codercto.com/a/10882.html)
		std::string name = request->name();
		// 2) 返回结果
		std::string message = std::string("Hello ") + name;
		// 提示: 通过set_xxx()函数设定
		reply->set_message(message);
		std::cout << "SayHello ->" << reply->message() << std::endl;
		// 3)  返回状态码
		//提示: Status::OK是一个类静态成员变量,不是枚举!!!
		return Status::OK;
		// 或者手动构造Status对象
		// return Status(grpc::INVALID_ARGUMENT, "未知参数");
	}
};

// 实现vno.proto/VnoService服务
class VnoServiceImpl final : public VnoService::Service {
	Status Run(ServerContext* context, const VnoRequest* request, VnoReply* reply) override {
		// 注意:graph是一个message对象, 不是原始数据类型, 用 hasXxx() 判断。
		//      不能用 getXxx() == null 判断
		if (!request->has_graph()) {
			// 设定返回结果
			reply->set_success(false);

			std::string error_message("graph参数未定义");
			std::cout << "VnoService::Run ->" << error_message << std::endl;
			return Status(grpc::INVALID_ARGUMENT, error_message);
		}
		else {
			reply->set_success(true);
			std::cout << "VnoService::Run ->" << "最大迭代次数:" << request->maxnumber() << std::endl;
			return Status::OK;
		}
	}
};

void RunServer() {
	// grpc服务器运行的本机ip(或者 localhost )
	std::string host = "0.0.0.0";
	// grpc服务器监听的端口
	int port = 50051;
	// 服务器完整地址
	std::string server_address(host + ":" + std::to_string(port));

	// 服务builder
	ServerBuilder builder;
	// Listen on the given address without any authentication mechanism.
	// 1) 监听端口
	// 注:InsecureChannelCredentials表示客户端与服务器之间的通信无权限验证,无加密(No SSL)
	builder.AddListeningPort(server_address, grpc::InsecureServerCredentials());

	// 2) 注册服务(可以注册多个Service)
	// Register "service" as the instance through which we'll communicate with
	// clients. In this case it corresponds to an *synchronous* service.
	// a. 注册GreetService服务
	GreeterServiceImpl service1;
	builder.RegisterService(&service1);
	// b. 注册VnoService服务
	VnoServiceImpl service2;
	builder.RegisterService(&service2);

	// 3) 启动服务器
	// Finally assemble the server.
	std::unique_ptr<Server> server(builder.BuildAndStart());
	std::cout << "Server listening on " << server_address << std::endl;

	// 4) 等待客户端连接
	// Wait for the server to shutdown. Note that some other thread must be
	// responsible for shutting down the server for this call to ever return.
	server->Wait();
}

int main(int argc, char** argv) {
	RunServer();

	return 0;
}
